/*
 * Copyright 2010-2012 Susanta Tewari. <freecode4susant@users.sourceforge.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package bd.org.apache.commons.math.stat.descriptive.moment;

import bd.org.apache.commons.math.exception.NullArgumentException;
import bd.org.apache.commons.math.util.MathUtils;

import java.io.Serializable;

/**
 * Computes a statistic related to the Second Central Moment.  Specifically,
 * what is computed is the sum of squared deviations from the sample mean.
 * <p>
 * The following recursive updating formula is used:</p>
 * <p>
 * Let <ul>
 * <li> dev = (current obs - previous mean) </li>
 * <li> n = number of observations (including current obs) </li>
 * </ul>
 * Then</p>
 * <p>
 * new value = old value + dev^2 * (n -1) / n.</p>
 * <p>
 * Returns <code>Double.NaN</code> if no data values have been added and
 * returns <code>0</code> if there is just one value in the data set.</p>
 * <p>
 * <strong>Note that this implementation is not synchronized.</strong> If
 * multiple threads access an instance of this class concurrently, and at least
 * one of the threads invokes the <code>increment()</code> or
 * <code>clear()</code> method, it must be synchronized externally.</p>
 *
 * @version $Id: SecondMoment.java 1244107 2012-02-14 16:17:55Z erans $
 */
public class SecondMoment extends FirstMoment implements Serializable {

    /** Serializable version identifier */
    private static final long serialVersionUID = 3942403127395076445L;

    /** second moment of values that have been added */
    protected double m2;

    /**
     * Create a SecondMoment instance
     */
    public SecondMoment() {

        super();

        m2 = Double.NaN;
    }

    /**
     * Copy constructor, creates a new {@code SecondMoment} identical
     * to the {@code original}
     *
     * @param original the {@code SecondMoment} instance to copy
     */
    public SecondMoment(SecondMoment original) {

        super(original);

        this.m2 = original.m2;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void increment(final double d) {

        if (n < 1) {
            m1 = m2 = 0.0;
        }

        super.increment(d);

        m2 += ((double) n - 1) * dev * nDev;
    }


    /**
     * {@inheritDoc}
     */
    @Override
    public void clear() {

        super.clear();

        m2 = Double.NaN;
    }


    /**
     * {@inheritDoc}
     */
    @Override
    public double getResult() {

        return m2;
    }


    /**
     * {@inheritDoc}
     */
    @Override
    public SecondMoment copy() {

        SecondMoment result = new SecondMoment();

        copy(this, result);

        return result;
    }


    /**
     * Copies source to dest.
     * <p>Neither source nor dest can be null.</p>
     *
     * @param source SecondMoment to copy
     * @param dest SecondMoment to copy to
     * @throws NullArgumentException if either source or dest is null
     */
    public static void copy(SecondMoment source, SecondMoment dest) throws NullArgumentException {

        MathUtils.checkNotNull(source);
        MathUtils.checkNotNull(dest);
        FirstMoment.copy(source, dest);

        dest.m2 = source.m2;
    }
}
